using System;
using System.Collections;
using System.Collections.Generic;
using ProtoModels;
using UnityEngine;

public class GGSnapshotCloudSync : GGFileIOCloudSync
{
	public delegate void OnConflictResolved();

	public delegate void OnConflict(CloudSyncConflict conflict);

	private class PendingSynchronizeNowRequests
	{
		public GGServerRequestsBackend.OnComplete onComplete;
	}

	public class CloudSyncConflict
	{
		private GGServerRequestsBackend.CloudSyncRequest conflictRequest;

		public bool isResolved { get; protected set; }

		public CloudSyncConflict(GGServerRequestsBackend.CloudSyncRequest conflictRequest)
		{
			this.conflictRequest = conflictRequest;
			isResolved = false;
		}

		public void CancelConflict()
		{
			isResolved = true;
		}

		public void ResolveConflictUsingServerVersion()
		{
			if (!isResolved)
			{
				CloudSyncData response = conflictRequest.GetResponse<CloudSyncData>();
				GGSnapshotCloudSync gGSnapshotCloudSync = GGFileIOCloudSync.instance as GGSnapshotCloudSync;
				gGSnapshotCloudSync.ResolveConflictTakeTheirs(response);
				isResolved = true;
			}
		}

		public void ResolveConflictUsingLocalVersion()
		{
			if (!isResolved)
			{
				CloudSyncData response = conflictRequest.GetResponse<CloudSyncData>();
				GGSnapshotCloudSync gGSnapshotCloudSync = GGFileIOCloudSync.instance as GGSnapshotCloudSync;
				gGSnapshotCloudSync.ResolveConflictTakeMine(response);
				isResolved = true;
			}
		}
	}

	public const string MESSAGE_CONFLICT_RESOLVED = "MessageConflictResolved";

	private List<PendingSynchronizeNowRequests> pendingSyncRequests = new List<PendingSynchronizeNowRequests>();

	private GGServerRequestsBackend.ServerRequest lastFinishedRequest;

	private GGServerRequestsBackend.CloudSyncRequest inProgressRequest;

	private CloudSyncConflict conflict;

	private string snapshotSyncFileName = "snapshotSync.bytes";

	private SnapshotSyncInfo activeSnapshot;

	private GGSnapshotFileIO syncFileIO;

	private bool isSynchronizationInProgress
	{
		get
		{
			return inProgressRequest != null;
		}
	}

	private bool haveLocalChanges
	{
		get
		{
			return activeSnapshot.serverAcceptedGuid != activeSnapshot.localGuid;
		}
	}

	private bool isInConflict
	{
		get
		{
			return conflict != null && !conflict.isResolved;
		}
	}

	public event OnConflict onConflict;

	public void SaveActiveSnapshot()
	{
		ProtoIO.SaveToFile(snapshotSyncFileName, activeSnapshot);
	}

	public void Init()
	{
		syncFileIO = new GGSnapshotFileIO(this);
		if (!ProtoIO.LoadFromFile<SnapshotSyncInfo>(snapshotSyncFileName, out activeSnapshot))
		{
			activeSnapshot = new SnapshotSyncInfo();
			activeSnapshot.localSnapVersion = -1;
			activeSnapshot.serverSnapSentVersion = -1;
			activeSnapshot.serverSnapAcceptedVersion = -1;
			SaveActiveSnapshot();
		}
		StartCoroutine(DoPeriodicallyTryToSync());
	}

	public override GGFileIO GetDefaultFileIO()
	{
		if (GGPlayerSettings.instance.Model.canCloudSync)
		{
			return syncFileIO;
		}
		return GGFileIO.instance;
	}

	public override GGFileIO GetCloudFileIO()
	{
		return syncFileIO;
	}

	public void UpdateSnapshot()
	{
		activeSnapshot.localGuid = Guid.NewGuid().ToString();
		SaveActiveSnapshot();
	}

	private IEnumerator DoPeriodicallyTryToSync()
	{
		while (true)
		{
			float ellapsedSecondsSinceHaveLocalChanges2 = 0f;
			float cloudSyncTimeDelaySeconds = ((lastFinishedRequest == null || lastFinishedRequest.status == GGServerRequestsBackend.ServerRequest.RequestStatus.Success) ? ConfigBase.instance.cloudSyncTimeDelay : ConfigBase.instance.cloudSyncTimeDelayWhenRequestFails);
			while (!haveLocalChanges || !ConfigBase.instance.IsSyncEnabledInCurrentScene() || ellapsedSecondsSinceHaveLocalChanges2 < cloudSyncTimeDelaySeconds)
			{
				ellapsedSecondsSinceHaveLocalChanges2 = ((!haveLocalChanges) ? 0f : (ellapsedSecondsSinceHaveLocalChanges2 + RealTime.deltaTime));
				yield return null;
			}
			ellapsedSecondsSinceHaveLocalChanges2 = 0f;
			SynchronizeIfPossible();
			while (isSynchronizationInProgress || isInConflict)
			{
				yield return null;
			}
		}
	}

	private void SynchronizeIfPossible()
	{
		if (!isSynchronizationInProgress && !isInConflict)
		{
			SynchronizeNow(HandleSyncRequestResult);
		}
	}

	public void SynchronizeNow(GGServerRequestsBackend.OnComplete onComplete)
	{
		Debug.Log("Sync now");
		if (isSynchronizationInProgress)
		{
			PendingSynchronizeNowRequests pendingSynchronizeNowRequests = new PendingSynchronizeNowRequests();
			pendingSynchronizeNowRequests.onComplete = onComplete;
			PendingSynchronizeNowRequests item = pendingSynchronizeNowRequests;
			pendingSyncRequests.Add(item);
		}
		else
		{
			DoSynchronize(onComplete);
		}
	}

	private void DoSynchronize(GGServerRequestsBackend.OnComplete onComplete)
	{
		inProgressRequest = CreateRequest();
		BehaviourSingletonInit<GGServerRequestsBackend>.instance.GetCSData(inProgressRequest, delegate(GGServerRequestsBackend.ServerRequest request)
		{
			lastFinishedRequest = request;
			inProgressRequest = null;
			onComplete(request);
		});
	}

	private GGServerRequestsBackend.CloudSyncRequest CreateRequest()
	{
		if (isInConflict)
		{
			conflict.CancelConflict();
		}
		if (haveLocalChanges)
		{
			Debug.Log("cloud sync update");
			List<string> files = ConflictResolverBase.instance.FilesToSync();
			CloudSyncData snapshotForSync = GetSnapshotForSync(files);
			GGServerRequestsBackend.UpdateCloudSyncDataRequest updateCloudSyncDataRequest = new GGServerRequestsBackend.UpdateCloudSyncDataRequest();
			updateCloudSyncDataRequest.AddData(snapshotForSync);
			updateCloudSyncDataRequest.SetVersionInfo(activeSnapshot.serverSnapAcceptedVersion + 1, activeSnapshot.localGuid);
			return updateCloudSyncDataRequest;
		}
		Debug.Log("cloud sync get");
		GGServerRequestsBackend.GetCloudSyncDataRequest getCloudSyncDataRequest = new GGServerRequestsBackend.GetCloudSyncDataRequest();
		getCloudSyncDataRequest.SetVersionInfo(activeSnapshot.serverSnapAcceptedVersion, activeSnapshot.localGuid);
		return getCloudSyncDataRequest;
	}

	public void HandleSyncRequestResult(GGServerRequestsBackend.ServerRequest request)
	{
		Debug.Log("on cloud sync finished");
		GGServerRequestsBackend.CloudSyncRequest cloudSyncRequest = request as GGServerRequestsBackend.CloudSyncRequest;
		if (request.status != 0)
		{
			HandlePendingRequests();
			return;
		}
		CloudSyncData response = request.GetResponse<CloudSyncData>();
		Debug.Log(activeSnapshot.serverSnapAcceptedVersion + " " + cloudSyncRequest.snapshotId + " " + response.snapshotId + " server GUID " + response.snapshotGUID);
		bool flag = response.snapshotGUID == cloudSyncRequest.snapshotGUID;
		bool flag2 = cloudSyncRequest is GGServerRequestsBackend.UpdateCloudSyncDataRequest;
		bool flag3 = cloudSyncRequest.snapshotGUID != activeSnapshot.localGuid;
		bool flag4 = response.snapshotId > cloudSyncRequest.snapshotId;
		bool flag5 = !string.IsNullOrEmpty(response.snapshotGUID);
		if (!flag2 && !flag3 && flag4)
		{
			Debug.Log("shouldTakeNewServerVesion");
			ResolveConflictTakeTheirs(response);
		}
		else if (!flag && flag5)
		{
			Debug.Log("is in conflict");
			SetConflictedState(cloudSyncRequest);
		}
		else
		{
			Debug.Log("not in conflict");
			UpdateLastKnownServerValues(response.snapshotId, response.snapshotGUID, activeSnapshot.localGuid);
		}
		Debug.Log(activeSnapshot.serverSnapAcceptedVersion + " " + cloudSyncRequest.snapshotId + " " + response.snapshotId);
		HandlePendingRequests();
		if (isInConflict && !isSynchronizationInProgress && this.onConflict != null)
		{
			this.onConflict(conflict);
		}
	}

	public void HandlePendingRequests()
	{
		if (pendingSyncRequests.Count > 0)
		{
			PendingSynchronizeNowRequests pendingSynchronizeNowRequests = pendingSyncRequests[0];
			pendingSyncRequests.RemoveAt(0);
			DoSynchronize(pendingSynchronizeNowRequests.onComplete);
		}
	}

	private void UpdateLastKnownServerValues(int serverSnapshotId, string serverSnapshotGUID, string localGUID)
	{
		activeSnapshot.serverSnapAcceptedVersion = serverSnapshotId;
		activeSnapshot.serverAcceptedGuid = serverSnapshotGUID;
		activeSnapshot.localGuid = localGUID;
		SaveActiveSnapshot();
	}

	private void SetConflictedState(GGServerRequestsBackend.CloudSyncRequest conflictedRequest)
	{
		if (conflict != null)
		{
			conflict.CancelConflict();
		}
		conflict = new CloudSyncConflict(conflictedRequest);
	}

	public void ResolveConflictTakeTheirs(CloudSyncData serverResponseData)
	{
		foreach (CloudSyncData.CloudSyncFile file in serverResponseData.files)
		{
			byte[] bytes = Convert.FromBase64String(file.data);
			GGFileIO.instance.Write(file.key, bytes);
		}
		UpdateLastKnownServerValues(serverResponseData.snapshotId, serverResponseData.snapshotGUID, serverResponseData.snapshotGUID);
		ConflictResolverBase.instance.OnConflict();
		BehaviourSingleton<GGNotificationCenter>.instance.Broadcast("MessageConflictResolved");
	}

	public void ResolveConflictTakeMine(CloudSyncData serverResponseData)
	{
		UpdateLastKnownServerValues(serverResponseData.snapshotId, serverResponseData.snapshotGUID, serverResponseData.snapshotGUID);
		SynchronizeNow(HandleSyncRequestResult);
		synchronize();
		BehaviourSingleton<GGNotificationCenter>.instance.Broadcast("MessageConflictResolved");
	}

	private CloudSyncData GetSnapshotForSync(List<string> files)
	{
		CloudSyncData cloudSyncData = new CloudSyncData();
		cloudSyncData.snapshotId = activeSnapshot.localSnapVersion;
		cloudSyncData.snapshotGUID = activeSnapshot.localGuid;
		foreach (string file in files)
		{
			CloudSyncData.CloudSyncFile cloudSyncFile = new CloudSyncData.CloudSyncFile();
			cloudSyncFile.key = file;
			cloudSyncFile.guid = string.Empty;
			cloudSyncFile.revision = 0;
			byte[] array = syncFileIO.Read(file);
			cloudSyncFile.data = ((array == null) ? string.Empty : Convert.ToBase64String(array, 0, array.Length));
			cloudSyncData.files.Add(cloudSyncFile);
		}
		return cloudSyncData;
	}
}
